#include "pg_common.h"
#include "adduserdb.h"

int main(int argc, char **argv) {

   struct users *usert;
   char sql[512],buffer[256],pass[9];
   CONNECTION_DB conn;
   PGresult *result;
   int c, force=0;

   usert = (struct users *) malloc(sizeof(struct users));
   usert->user=NULL;
   usert->home=NULL;
   usert->group=NULL;
   usert->name=NULL;
   usert->comment=NULL;
   usert->shell=NULL;
   usert->matriculation="\0";
   usert->grade="\0";

   if(argc < 2) {
      print_help();
      exit(0);
   }

   while ( (c=getopt (argc, argv, "o:m:g:d:n:c:s:fh")) != -1 ) {

      switch (c) {

         case 'g':
            usert->group = strdup(optarg);
         break;

         case 'd':
            usert->home = strdup(optarg);
         break;

         case 'm':
	    usert->matriculation=strdup(optarg);  
         break;

         case 'o':
	    usert->grade = strdup(optarg);
	 break;
         
         case 'n':
            usert->name = strdup(optarg);
         break;

         case 's':
            usert->shell = strdup(optarg);
         break;

         case 'h':
           print_help();
           exit(0);
         break;

         case 'c':
            usert->comment = strdup(optarg);
         break;

         case 'f':
            force=1;
         break;

         case '?':
         break;

      }

   }

   if(optind < argc) {
      usert->user = strdup(argv[optind++]);
   } else {
      printf("\n     >> Usuario nao especificado << \n\n");
      print_help();
      exit(0);
   }

   if( usert->name == NULL || strlen(usert->name) < 2 ) {
      printf("\n     >> Nome nao especificado ou com menos de 2 caracteres << \n\n");
      print_help();
      exit(0);
   }
   
   if( usert->shell == NULL ) usert->shell = strdup("/bin/bash");
   if( usert->comment == NULL ) usert->comment = strdup("");
   if( usert->home == NULL ) { 
      sprintf(buffer, "/home/bcc/%s", usert->user);
      usert->home = strdup(buffer);
   }

   if( usert->group == NULL ) usert->group = strdup("bcc");

   if(geteuid() != 0) {
      printf("Somente o root pode executar esse comando\n");
      exit(0);
   }

   conn = init_db(DB_ARQ_CONF);
   if( PQstatus(conn->pgconn) != CONNECTION_OK || conn == NULL ) {
      printf("Falha na conexao\n");
      exit(0);
   }

   sprintf(sql, "SELECT * FROM user_sys WHERE login='%s'", usert->user);
   result = PQexec(conn->pgconn, sql);
   if(PQntuples(result)>0) {
      printf("Usuario ja existe\n");
      free_db(conn);
      exit(0);
   }

   sprintf(sql, "SELECT group_id FROM group_sys WHERE name='%s'", usert->group);
   result = PQexec(conn->pgconn, sql);
   if(PQntuples(result)==0) {
      printf("Grupo '%s' nao existe\n", usert->group);
      free_db(conn);
      exit(0);
   } else {
      usert->group_id = atoi(PQgetvalue(result,0,0));
   }


   if(force==0) {

      printf("Nome do usuario: %s\n", usert->name);
      printf("Login do usuario: %s\n", usert->user);
      printf("Grupo padrao: %s\n", usert->group);
      printf("Home: %s\n", usert->home);
      printf("Shell: %s\n", usert->shell);
      printf("Curso: %s\n", usert->grade);
      printf("Matricula: %s\n", usert->matriculation);
      printf("Comentario: %s\n", usert->comment);
      
      printf("As informacoes estao corretas? [s/n] ");
      while( (c=getchar()) != 's' && c != 'n' ) {
         printf("As informacoes estao corretas? [s/n] ");
         getchar();
      }
      if(c=='n') {
         free_db(conn);
         exit(0);
      }
   }

   gen_pass(pass);
   char *md5 = encrypt_password(pass);

   usert->user_id=last_user_id(conn);
   sprintf(sql, "INSERT INTO user_sys VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', 0);", usert->user_id, usert->group_id, usert->user, usert->name, usert->home, usert->shell, usert->comment);
   PQexec(conn->pgconn, sql);

   sprintf(sql, "INSERT INTO user_shadow VALUES (%d, '%s', 0, 6, 8, 0, 0, 0);", usert->user_id, md5);
   PQexec(conn->pgconn, sql);

   if(strlen(PQerrorMessage(conn->pgconn)) > 2)
      printf("Erro ao adicionar usuario %s: %s\n", usert->user, PQerrorMessage(conn->pgconn));
   
   else{
   
     time_t t = time(NULL);
          
     sprintf(sql, "INSERT INTO user_extended VALUES (%d, '%s',%d,'%s',%d,0);",usert->user_id,
	     usert->matriculation, (int)t,usert->grade,(int)t);
     
     PQexec(conn->pgconn, sql);
     
     if(strlen(PQerrorMessage(conn->pgconn)) > 2)
       printf("Erro ao adicionar atributos extendidos de usuario %s: %s\n", usert->user, 
	      PQerrorMessage(conn->pgconn));
     
   }
   if(addpasswd(usert->user, usert->user_id, usert->group_id, usert->comment, usert->home, usert->shell) == -1)
      printf("Erro ao adicionar no passwd\n");

   if(addshadow(usert->user) == -1)
      printf("Erro ao adicionar no shadow\n");

   
   free_db(conn);

   printf("Usuario adicionado '%s' : %s\n", usert->user, pass);

   return 0;

}

void print_help() {

   printf("Uso correto: adduserdb [options] LOGIN\n\n");
   printf("Opcoes:\n");
   printf("  -g\tGrupo padrao do usuario (padrao: bcc)\n");
   printf("  -d\tHome do usuario (padrao: /home/bcc/LOGIN)\n");
   //printf("  -GGrupos adicionais do usuario (ex: grupo1,grupo2)\n");
   printf("  -s\tBinario padrao de execucao ao login (padrao: /bin/bash)\n");
   printf("  -m\tMatricula (padrao: NULL)\n");
   printf("  -o\tcurso (padrao: NULL)\n");
   printf("  -c\tcomment(padrao: NULL)\n");
   printf("  -n\tNome do usuario (ex: -n \"Nome do cidadao\")\n");
   printf("  -f\tAdiciona sem pergunta se informacoes estao corretas\n");
   printf("  -h\tMostra essa ajuda\n");
   printf("\nSECURE DB USERS SYSTEM MANAGEMENT\n");

}

int last_user_id(CONNECTION_DB conn) {

   PGresult *result=NULL;

   result = PQexec(conn->pgconn, "SELECT user_id FROM user_sys ORDER BY user_id DESC LIMIT 1;");
   if( result != NULL && PQntuples(result) == 1 )
      return (atoi(PQgetvalue(result,0,0))+1);
   else
      return 1;

}

void gen_pass(char *pass) {

   FILE *fp;
   int num,read=1,i=0;

   fp = fopen("/dev/urandom", "r");
   if(fp==NULL) printf("erro\n");

   while(read==1) {
      num = (int) fgetc(fp);
      if( (num > 64 && num < 91) || (num > 96 && num < 123) ) {
         pass[i]=num;
         if(i==8) read=0;
         i++;
      }
   }
   pass[i]='\0';

}

char * encrypt_password(const char *pass) {

   char *s = NULL;
   char *buf;
   int buf_size;
   unsigned int i;
   MHASH handle;
   unsigned char *hash;

   handle = mhash_init(MHASH_SHA1);
   if(handle == MHASH_FAILED) {
      printf("Problema no mhash\n");
      exit(0);
   } else {
      mhash(handle, pass, strlen(pass));
      hash = mhash_end(handle);
      if (hash != NULL) {
         buf_size = (mhash_get_block_size(MHASH_SHA1) * 2)+1;
         buf = (char *)malloc(buf_size);
         bzero(buf, buf_size);

         for(i = 0; i < mhash_get_block_size(MHASH_SHA1); i++)
            sprintf(&buf[i * 2], "%.2x", hash[i]);

         free(hash);
         s = buf;
      } else {
         s = strdup("!");
      }

   }

   return s;

}

int addpasswd(char *login, int user_id, int group_id, char *comment, char *home, char *shell) {

   FILE *fp;
   char buffer[1024];

   fp = fopen(PASSWDFILE, "a");
   if(fp==NULL) return -1;

   sprintf(buffer, "%s:x:%d:%d:%s:%s:%s\n", login, user_id, group_id, comment, home, shell);

   fputs(buffer, fp);

   fclose(fp);
   return 0;

}

int addshadow(char *login) {

   FILE *fp;
   char buffer[1024];

   fp = fopen(SHADOWFILE, "a");
   if(fp==NULL) return -1;

   sprintf(buffer, "%s:!:0:0:::::\n", login);

   fputs(buffer, fp);

   fclose(fp);
   return 0;

}
